package com.base.library.base

import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.text.TextUtils
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.ViewTreeLifecycleOwner
import androidx.viewbinding.ViewBinding
import com.base.library.BR
import com.base.library.ext.listenTo
import com.base.library.ext.showToast
import com.base.library.utils.BarUtils
import com.base.library.utils.KeyboardUtils
import com.base.library.utils.ShareViewModelManager
import java.lang.reflect.ParameterizedType

abstract class BaseVMFragment<VM : BaseVM, VB : ViewDataBinding> : Fragment() {

    protected lateinit var mVm: VM
    protected lateinit var mVb: VB
    private var mLoadingDialog: LoadingDialog? = null

    private val mModelClass by lazy {
        val parameterizedType = javaClass.genericSuperclass as ParameterizedType
        parameterizedType.actualTypeArguments[0] as Class<VM>
    }

    open fun generateContentView(): ViewGroup? = null

    open fun getParentViewBinding(): ViewBinding? = null

    /**
     * 共享viewModel的key
     */
    open fun getShareViewModelKey(): String? = null

    open fun getViewModelStoreOwner(): ViewModelStoreOwner {
        return ShareViewModelManager.getShareViewOwner(getShareViewModelKey()) ?: this
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View? {
        initViewBinding(inflater)
        generateViewModel()
        return getParentViewBinding()?.root ?: mVb.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        listenToViewModelEvents(mVm)
        lifecycle.addObserver(mVm)
        mVb.setVariable(getViewModelId(), mVm)
        mVm.arguments = arguments
        mVm.initData()
    }

    override fun onResume() {
        super.onResume()
    }

    override fun onHiddenChanged(hidden: Boolean) {
        super.onHiddenChanged(hidden)
    }

    private fun generateViewModel() {
        try {
            mVm = ViewModelProvider(getViewModelStoreOwner())[mModelClass]
            ShareViewModelManager.putSharedViewModel(getShareViewModelKey(), this)
        } catch (_: Throwable) {

        }
    }

    private fun initViewBinding(inflater: LayoutInflater) {
        val parentView = generateContentView()
        mVb = if (parentView == null) {
            DataBindingUtil.inflate(inflater, getLayoutId(), null, false)
        } else {
            DataBindingUtil.inflate(inflater, getLayoutId(), parentView, true)
        }
        mVb.lifecycleOwner = this@BaseVMFragment
        ViewTreeLifecycleOwner.set(mVb.root, this)
    }

    private fun listenToViewModelEvents(viewModel: VM) {
        viewModel.mStartActivityFlow.listenTo(lifecycle) {
            it.startActivityForResult(this)
        }
        viewModel.mToastContentFlow.listenTo(lifecycle) {
            toast(it)
        }
        viewModel.isClosedSelf.listenTo(lifecycle) {
            if (it == true) {
                activity?.finish()
            }
        }
        viewModel.mHideKeyboard.listenTo(lifecycle) {
            if (it == true) {
                KeyboardUtils.hideSoftInput(activity)
            }
        }
        viewModel.mLoadingDialogFlow.listenTo(lifecycle) {
            if (TextUtils.isEmpty(it)) {
                mLoadingDialog?.dismissAllowingStateLoss()
                return@listenTo
            }
            if (mLoadingDialog?.dialog?.isShowing == true) {
                return@listenTo
            }
            mLoadingDialog = LoadingDialog()
            mLoadingDialog?.show(childFragmentManager, "LoadingDialog")
        }
    }

    open fun toast(msg: CharSequence?) {
        msg?.let {
            context?.showToast(it)
        }
    }

    @Deprecated("Deprecated in Java")
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        mVm.onActivityResult(
            code = requestCode, result = data, resultCode = resultCode
        )
    }

    override fun onDestroyView() {
        super.onDestroyView()
    }

    open fun getViewModelId(): Int = BR.vm

    abstract fun getLayoutId(): Int
}
